var qs = require('querystring');

var utils = require('../utils');

const END_POINTS = {
    GET_TOKEN : '/cgi-bin/token', //?grant_type=client_credential&appid=APPID&secret=APPSECRET
    GET_TICKET: '/cgi-bin/ticket/getticket', //?access_token=ACCESS_TOKEN&type=jsapi
    DOWNLOAD_MEDIA: '/cgi-bin/media/get', //?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
    CONNECT_OAUTH2: '/connect/oauth2/authorize', //?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
    SNS_GET_TOKEN : '/sns/oauth2/access_token', //?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
    COMPONENT_ACCESS_TOKEN: '/cgi-bin/component/api_component_token', //POST '{"component_appid":"appid_value" , "component_appsecret": "appsecret_value", "component_verify_ticket": "ticket_value"}'
    PRE_AUTH_CODE: '/cgi-bin/component/api_create_preauthcode', //?component_access_token=$your_access_token POST: '{"component_appid":"appid_value"}'
    MP_OAUTH_URL: '/cgi-bin/componentloginpage', //?component_appid=$your_appid&pre_auth_code=$your_pre_auth_code&redirect_uri=$your_own_redirect_uri'
    GET_AUTHORIZER_TOKEN: '/cgi-bin/component/api_query_auth', //?component_access_token=xxxx POST: {"component_appid":"appid_value" ,"authorization_code": "auth_code_value"}
    REFRESH_AUTHORIZER_TOKEN: '/cgi-bin/component/api_authorizer_token', //?component_access_token=xxxxx'
    GET_AUTHORIZER_INFO: '/cgi-bin/component/api_get_authorizer_info', //?component_access_token=xxxx'
    USER_OAUTH_URL: '/connect/oauth2/authorize', //?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
    USER_OAUTH_TOKEN: '/sns/oauth2/access_token', //?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
    COMPONENT_USER_OAUTH_TOKEN: '/sns/oauth2/component/access_token', //?appid=APPID&code=CODE&grant_type=authorization_code&component_appid=COMPONENT_APPID&component_access_token=COMPONENT_ACCESS_TOKEN
    SNS_USER_INFO: '/sns/userinfo', //?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
    USER_INFO: '/cgi-bin/user/info', //?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
    GET_MEDIA: '/cgi-bin/media/get', //?access_token=ACCESS_TOKEN&media_id=MEDIA_ID

    QR_CODE: '/cgi-bin/qrcode/create', //?access_token=Token
    SHOW_QR_CODE: '/cgi-bin/showqrcode', //?ticket=TICKET
    // * Section Start: WeChat Customer Service API
    SEND_CUSTOMER_SERVICE_MESSAGE: '/cgi-bin/message/custom/send'
    // * Section End: WeChat Customer Service API
};

const SNS_END_POINTS = {
    SNS_GET_TOKEN : '/sns/oauth2/access_token', //?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
    SNS_USER_INTO: '/sns/userinfo', //?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
    USER_OAUTH_URL: '/connect/oauth2/authorize', //?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
};

const MP_END_POINTS = {
    MP_OAUTH_URL: '/cgi-bin/componentloginpage', //?component_appid=$your_appid&pre_auth_code=$your_pre_auth_code&redirect_uri=$your_own_redirect_uri'
    SHOW_QR_CODE: '/cgi-bin/showqrcode', //?ticket=TICKET
};


const WECHAT_SERVER = "https://api.weixin.qq.com";
const WECHAT_SNS_SERVER = "https://open.weixin.qq.com";
const WECHAT_MP_SERVER = 'https://mp.weixin.qq.com';

/**
 * Use this const to represent different WeChat endpoint
 */
const ENDPOINT_KEYS = {
    GET_TOKEN : "GET_TOKEN",
    GET_TICKET: "GET_TICKET",
    DOWNLOAD_MEDIA: "DOWNLOAD_MEDIA",
    CONNECT_OAUTH2: "CONNECT_OAUTH2",
    COMPONENT_ACCESS_TOKEN: "COMPONENT_ACCESS_TOKEN",
    PRE_AUTH_CODE: "PRE_AUTH_CODE",
    MP_OAUTH_URL: "MP_OAUTH_URL",
    GET_AUTHORIZER_TOKEN: "GET_AUTHORIZER_TOKEN",
    REFRESH_AUTHORIZER_TOKEN: "REFRESH_AUTHORIZER_TOKEN",
    GET_AUTHORIZER_INFO: "GET_AUTHORIZER_INFO",
    USER_OAUTH_URL: "USER_OAUTH_URL",
    USER_OAUTH_TOKEN: "USER_OAUTH_TOKEN",
    COMPONENT_USER_OAUTH_TOKEN: "COMPONENT_USER_OAUTH_TOKEN",
    SNS_USER_INFO: "SNS_USER_INFO",
    USER_INFO: "USER_INFO",
    GET_MEDIA: "GET_MEDIA",
    QR_CODE: "QR_CODE",
    SHOW_QR_CODE: "SHOW_QR_CODE",
    SEND_CUSTOMER_SERVICE_MESSAGE: "SEND_CUSTOMER_SERVICE_MESSAGE"
};

exports.END_POINTS = ENDPOINT_KEYS;


const SNS_ENDPOINT_KEYS = {
    SNS_GET_TOKEN : "SNS_GET_TOKEN",
    USER_OAUTH_URL: "USER_OAUTH_URL"
};

exports.SNS_END_POINTS = SNS_ENDPOINT_KEYS;

const MP_ENDPOINT_KEYS = {
    MP_OAUTH_URL: "MP_OAUTH_URL",
    SHOW_QR_CODE: "SHOW_QR_CODE"
};

exports.MP_END_POINTS = MP_ENDPOINT_KEYS;

/**
 * WeChat api utilities class
 * 
 * @name WeChatApiHelper
 */
class WeChatApiHelper {
    /**
     * Get wechat server endpoint
     * 
     * @name getWeChatServerEndPoint
     * @param {String} endpoint - the endpoint key
     * @param {Object} params - the parameters which will be passed to this endpoint
     * 
     * @returns {String}
     */
    static getWeChatServerEndPoint(endpoint, params) {
        if(params && typeof params === 'object') {
            return `${WECHAT_SERVER}${END_POINTS[endpoint]}?${qs.stringify(params)}`;
        } else {
            return `${WECHAT_SERVER}${END_POINTS[endpoint]}`;
        }
    }

    /**
     * Get wechat sns server endpoint
     * 
     * @name getWeChatSNSServerEndPoint
     * @param {String} endpoint - the endpoint key
     * @param {Object} params - the parameters which will be passed to this endpoint
     * 
     * @returns {String}
     */
    static getWeChatSNSServerEndPoint(endpoint, params) {
        if(params && typeof params === 'object') {
            return `${WECHAT_SNS_SERVER}${SNS_END_POINTS[endpoint]}?${qs.stringify(params)}`;
        } else {
            return `${WECHAT_SNS_SERVER}${SNS_END_POINTS[endpoint]}`
        }
    }

    /**
     * Get wechat mp server endpoint
     * 
     * @name getWeChatMPServerEndPoint
     * @param {String} endpoint - the endpoint key
     * @param {Object} params - the parameters which will be passed to this endpoint
     * 
     * @returns {String}
     */
    static getWeChatMPServerEndPoint(endpoint, params) {
        if(params && typeof params === 'object') {
            return `${WECHAT_MP_SERVER}${MP_END_POINTS[endpoint]}?${qs.stringify(params)}`;
        } else {
            return `${WECHAT_MP_SERVER}${MP_END_POINTS[endpoint]}`
        }
    }
}

exports.WeChatApiHelper = WeChatApiHelper;


/**
 * This is one helper class which is used for generate different message
 * 
 * @name WeChatMessageHelper
 */
class WeChatMessageHelper {

    /**
     * Get customer text message
     * 
     * @name getCustomerTextMessage
     * @param {String} openId - the recipient's wechat openId
     * @param {String} content - the text message which will send to recipient
     * 
     * @returns {Object}
     */
    static getCustomerTextMessage(openId, content) {
        return {
            "touser" : openId,
            "msgtype" : "text",
            "text" : {
                "content" : content
            }
        };
    }

    /**
     * Get customer image message
     * 
     * @name getCustomerImageMessage
     * @param {String} openId - the recipient's wechat openId
     * @param {String} mediaId - the media_id of image in WeChat
     * 
     * @returns {Object} 
     */
    static getCustomerImageMessage(openId, mediaId) {
        return {
            "touser" : openId,
            "msgtype" : "image",
            "image" : {
                "media_id" : mediaId
            }
        };
    }

    /**
     * Get customer voice message
     * 
     * @name getCustomerVoiceMessage
     * @param {String} openId - the recipient's wechat openId
     * @param {String} mediaId - the media_id of voice in WeChat 
     * 
     * @returns {Object}
     */
    static getCustomerVoiceMessage(openId, mediaId) {
        return {
            "touser" : openId,
            "msgtype" : "voice",
            "voice" : {
                "media_id" : mediaId
            }
        };
    }

    /**
     * Get customer news message
     * 
     * @param {String} openId - The recipient's openId
     * @param {Array} articles - The news articles
     * 
     * @returns {Object}
     * 
     * @memberOf WeChatMessageHelper
     */
    static getCustomerNewsMessage(openId, articles) {
        utils.checkStringParameter(openId, "openId");
        utils.checkArrayParameter(articles, "articles");

        return {
            "touser" : openId,
            "msgtype" : "news",
            "news" : {
                "articles" : articles
            }
        };
    }


    /**
     * Get wechat text reply message
     * 
     * @name getReplyTextMessage
     * @param {String} fromUser - the openId of the wechat offical account
     * @param {String} toUser - the recipient's wechat openId
     * @param {String} content - the text message content
     * 
     * @returns {String}
     */
    static getReplyTextMessage(fromUser, toUser, content) {

        return '<xml>' + 
                    `<ToUserName><![CDATA[${toUser}]]></ToUserName>` +
                    `<FromUserName><![CDATA[${fromUser}]]></FromUserName>` +
                    `<CreateTime>${utils.getWeChatCreateTime()}</CreateTime>` +
                    '<MsgType><![CDATA[text]]></MsgType>' +
                    `<Content><![CDATA[${content}]]></Content>` +
               '</xml>';
    }


    /**
     * Get wechat image reply message
     * 
     * @description About the media_id, please check {@link https://mp.weixin.qq.com/wiki/15/2d353966323806a202cd2deaafe8e557.html|素材管理}
     * 
     * @name getReplyImageMessage
     * @param {String} fromUser - the openId of the wechat offical account
     * @param {String} toUser - the recipient's wechat openId
     * @param {String} mediaId - the media_id of image in WeChat
     * 
     * @returns {String}
     */
    static getReplyImageMessage(fromUser, toUser, mediaId) {
        return '<xml>' +
                    `<ToUserName><![CDATA[${toUser}]]></ToUserName>` +
                    `<FromUserName><![CDATA[${fromUser}]]></FromUserName>` +
                    `<CreateTime>${utils.getWeChatCreateTime()}</CreateTime>` +
                    '<MsgType><![CDATA[image]]></MsgType>' +
                    '<Image>' +
                    `<MediaId><![CDATA[${mediaId}]]></MediaId>` +
                    '</Image>' +
                '</xml>';
    }

    /**
     * Get wechat news reply message
     * 
     * @description getReplyNewsMessage
     * @param {String} fromUser - the openId of the wechat offical account
     * @param {String} toUser - the recipient's wechat openId
     * @param {String} news - the array of articles
     * 
     * @returns {String}
     */
    static getReplyNewsMessage(fromUser, toUser, news) {
        let header = '<xml>' + 
                `<ToUserName><![CDATA[${toUser}]]></ToUserName>` + 
                `<FromUserName><![CDATA[${fromUser}]]></FromUserName>` +
                `<CreateTime>${utils.getWeChatCreateTime()}</CreateTime>` + 
                `<MsgType><![CDATA[news]]></MsgType>` + 
                `<ArticleCount>${news.length}</ArticleCount>` +
                '<Articles>';

        let articles = '';
        news.forEach((article) => {
            articles += '<item>' +
                (article.title ? `<Title><![CDATA[${article.title}]]></Title>` : '') +
                (article.description ? `<Description><![CDATA[${article.description}]]></Description>` : '') + 
                (article.picurl ? `<PicUrl><![CDATA[${article.picurl}]]></PicUrl>` : '') +
                (article.url ? `<Url><![CDATA[${article.url}]]></Url>` : '') + 
                '</item>';
        });
        let footer = '</Articles></xml>';

        return `${header}${articles}${footer}`;
    }

    /**
     * Get wechat encrypted reply message
     * 
     * @name getReplyEncryptMessage
     * @param {String} toUser - The recipient's openId
     * @param {String} encryptContent - The encrypted content
     * 
     * @return {String}
     */
    static getReplyEncryptMessage(toUser, encryptedContent) {
        return '<xml>' +
                    `<ToUserName><![CDATA[${toUser}]]` +
                    `<Encrypt><![CDATA[${encryptedContent.Encrypt}]]></Encrypt>` +
                    `<MsgSignature><![CDATA[${encryptedContent.MsgSignature}]]</MsgSignature>` +
               '</xml>';
    }
}

exports.WeChatMessageHelper = WeChatMessageHelper;
